﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace YYS
{
    /// <summary>
    /// API方法
    /// </summary>
    public static class API
    {
        /// <summary>
        /// ContentType
        /// </summary>
        public struct ContentType
        {
            /// <summary>
            /// application/json
            /// </summary>
            public const string Json = "application/json";
            /// <summary>
            /// application/x-www-form-urlencoded
            /// </summary>
            public const string Form = "application/x-www-form-urlencoded";
            /// <summary>
            /// text/xml;charset=utf-8
            /// </summary>
            public const string Xml = "text/xml;charset=utf-8";
        }

        /// <summary>
        /// 获取应用程序启动目录
        /// </summary>
        /// <returns></returns>
        public static string getAppRoot()
        {
            return System.AppDomain.CurrentDomain.BaseDirectory;
        }

        /// <summary>
        /// 获取Web应用程序目录
        /// </summary>
        /// <param name="virtualPath">路径</param>
        /// <returns></returns>
        public static string getHostPath(string virtualPath)
        {
            return System.Web.Hosting.HostingEnvironment.MapPath(virtualPath);
        }

        /// <summary>
        /// 获取AppSettings配置值
        /// </summary>
        /// <param name="key">key</param>
        /// <param name="isRefreshSection">是否刷新节点</param>
        /// <returns></returns>
        public static string getAppSettings(string key, bool isRefreshSection = false)
        {
            if (isRefreshSection) System.Configuration.ConfigurationManager.RefreshSection("AppSettings");
            return System.Configuration.ConfigurationManager.AppSettings[key];
        }

       

        #region 时间
        /// <summary>
        /// 时间精度
        /// </summary>
        public enum DatePart
        {
            /// <summary>
            /// 毫秒
            /// </summary>
            Millisecond,
            /// <summary>
            /// 秒
            /// </summary>
            Second
        }
        /// <summary>
        /// 获取时间对应的时间戳
        /// </summary>
        /// <param name="Time">时间</param>
        /// <param name="datepart">时间精度，默认：Millisecond</param>
        /// <returns></returns>
        public static long jGetTimeStamp(this System.DateTime Time, DatePart datepart = DatePart.Millisecond)
        {
            DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1, 0, 0, 0, 0));
            long unixTime = datepart == DatePart.Millisecond ? (long)Math.Round((Time - startTime).TotalMilliseconds, MidpointRounding.AwayFromZero)
                : (long)Math.Round((Time - startTime).TotalSeconds, MidpointRounding.AwayFromZero);
            return unixTime;
        }
        /// <summary>
        /// 获取时间戳对应的时间
        /// </summary>
        /// <param name="timeStamp">时间戳</param>
        /// <param name="datepart">时间精度，默认：Millisecond</param>
        /// <returns></returns>
        public static DateTime? jGetTime(this string timeStamp, DatePart datepart = DatePart.Millisecond)
        {
            DateTime? dtResult = null;
            if (timeStamp.jTrim().Length == 0 || !timeStamp.JIsMatch(@"^\d{1,}$")) return dtResult;
            System.DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1, 0, 0, 0, 0));
            long d;
            if (long.TryParse(timeStamp, out d))
            {
                dtResult = datepart == DatePart.Millisecond ? startTime.AddMilliseconds(d)
                    : startTime.AddSeconds(d);
            }
            return dtResult;
        }
        /// <summary>
        /// 格式化时间
        /// </summary>
        /// <param name="dateTime">时间</param>
        /// <param name="format">格式</param>
        /// <returns></returns>
        public static string jFormatTime(this DateTime? dateTime, string format)
        {
            return dateTime == null ? "" : ((DateTime)dateTime).jFormatTime(format);
        }
        /// <summary>
        /// 格式化时间
        /// </summary>
        /// <param name="dateTime">时间</param>
        /// <param name="format">格式</param>
        /// <returns></returns>
        public static string jFormatTime(this DateTime dateTime, string format)
        {
            return string.Format("{0:" + format.Replace("{", "{{").Replace("}", "}}") + "}", dateTime);
        }
        #endregion

        #region UDP
        /// <summary>
        /// UDP发送
        /// </summary>
        /// <param name="ip">服务器IP</param>
        /// <param name="port">服务器端口</param>
        /// <param name="content">要发送的内容</param>
        /// <param name="encoding">编码方式</param>
        /// <returns>成功返回null，否则返回错误信息</returns>
        public static string sendUDP(string ip, int port, string content, System.Text.Encoding encoding)
        {
            ip = (ip ?? string.Empty).Trim();
            if (ip.Length == 0) return "ip 不能为空";
            if (port < 1025 || port > 65534) return "port 不可使用系统端口[0-1024,65535]";
            content = (content ?? string.Empty).Trim();
            if (content.Length == 0) return "content 不能为空";

            try
            {
                using (System.Net.Sockets.Socket socket = new System.Net.Sockets.Socket(System.Net.Sockets.AddressFamily.InterNetwork, System.Net.Sockets.SocketType.Dgram, System.Net.Sockets.ProtocolType.Udp))
                {
                    socket.Bind(new System.Net.IPEndPoint(System.Net.IPAddress.Any, 0));
                    System.Net.IPEndPoint iPEndPoint = new System.Net.IPEndPoint(System.Net.IPAddress.Parse(ip), port);
                    System.Net.EndPoint remoteEP = iPEndPoint;
                    byte[] bytes = encoding.GetBytes(content);
                    socket.SendTo(bytes, remoteEP);
                }
                return null;
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }
        /// <summary>
        /// UDP发送（UTF8编码）
        /// </summary>
        /// <param name="ip">服务器IP</param>
        /// <param name="port">服务器端口</param>
        /// <param name="content">要发送的内容</param>
        /// <returns>成功返回null，否则返回错误信息</returns>
        public static string sendUDP(string ip, int port, string content)
        {
            return sendUDP(ip, port, content, System.Text.Encoding.UTF8);
        }
        #endregion

        #region 校验身份证
        /// <summary>
        /// 校验身份证
        /// </summary>
        /// <param name="idNum"></param>
        /// <returns></returns>
        public static bool jIsIDNumber(this string idNum)
        {
            if (idNum == null) return false;
            if (idNum.Length != 15 && idNum.Length != 18) return false;
            string Ai = "";

            // ================ 数字 除最后以为都为数字 ================
            if (idNum.Length == 18)
            {
                Ai = idNum.Substring(0, 17);
            }
            else if (idNum.Length == 15)
            {
                Ai = idNum.Substring(0, 6) + "19" + idNum.Substring(6, 9);
            }
            if (!new System.Text.RegularExpressions.Regex("^[0-9]*$").IsMatch(Ai)) return false;
            // =======================(end)========================

            // ================ 出生年月是否有效 ================
            string strYear = Ai.Substring(6, 4);// 年份
            string strMonth = Ai.Substring(10, 2);// 月份
            string strDay = Ai.Substring(12, 2);// 月份
            DateTime Birth;
            if (!DateTime.TryParse(strYear + "-" + strMonth + "-" + strDay, out Birth)) return false;
            if (Birth >= DateTime.Parse(DateTime.Now.AddDays(1).ToString("yyyy-MM-dd"))) return false;
            // =====================(end)=====================

            // ================ 地区码是否有效 ================
            var dicArea = new Dictionary<string, string>() { { "11", "北京" }, { "12", "天津" }, { "13", "河北" }, { "14", "山西" }, { "15", "内蒙古" }, { "21", "辽宁" }, { "22", "吉林" }, { "23", "黑龙江" }, { "31", "上海" }, { "32", "江苏" }, { "33", "浙江" }, { "34", "安徽" }, { "35", "福建" }, { "36", "江西" }, { "37", "山东" }, { "41", "河南" }, { "42", "湖北" }, { "43", "湖南" }, { "44", "广东" }, { "45", "广西" }, { "46", "海南" }, { "50", "重庆" }, { "51", "四川" }, { "52", "贵州" }, { "53", "云南" }, { "54", "西藏" }, { "61", "陕西" }, { "62", "甘肃" }, { "63", "青海" }, { "64", "宁夏" }, { "65", "新疆" }, { "71", "台湾" }, { "81", "香港" }, { "82", "澳门" }, { "91", "国外" } };
            if (!dicArea.ContainsKey(Ai.Substring(0, 2))) return false;
            // ==============================================

            if (idNum.Length == 18)
            {
                string[] ValCodeArr = { "1", "0", "x", "9", "8", "7", "6", "5", "4", "3", "2" };
                string[] Wi = { "7", "9", "10", "5", "8", "4", "2", "1", "6", "3", "7", "9", "10", "5", "8", "4", "2" };

                int TotalmulAiWi = 0;
                for (int i = 0; i < 17; i++)
                {
                    TotalmulAiWi = TotalmulAiWi + int.Parse(Ai[i].ToString()) * int.Parse(Wi[i]);
                }
                int modValue = TotalmulAiWi % 11;
                String strVerifyCode = ValCodeArr[modValue];
                Ai = Ai + strVerifyCode;

                if (!Ai.Equals(idNum, StringComparison.OrdinalIgnoreCase)) return false;
            }
            return true;
        }
        #endregion

        #region 图片验证码
        /// <summary>
        /// 生成随机数
        /// </summary>
        /// <param name="aCount">随机数长度</param>
        /// <returns></returns>
        public static string zRandom(int aCount)
        {
            string allChar = "0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,G,H,I,J,K,O,P,Q,R,S,T,U,W,X,Y,Z,a,b,c,d,e,f,g,h,i,j,k,m,n,o,p,q,s,t,u,w,x,y,z";
            string[] allCharArray = allChar.Split(',');//拆分成数组
            string randomNum = "";
            int temp = -1;                             //记录上次随机数的数值，尽量避免产生几个相同的随机数
            Random rand = new Random();
            for (int i = 0; i < aCount; i++)
            {
                if (temp != -1)
                {
                    rand = new Random(i * temp * ((int)DateTime.Now.Ticks));
                }
                int t = rand.Next(35);
                if (temp == t)
                {
                    return zRandom(aCount);
                }
                temp = t;
                randomNum += allCharArray[t];
            }
            return randomNum;
        }
        /// <summary>
        /// 生成验证码图片
        /// </summary>
        /// <param name="aCode"></param>
        /// <returns></returns>
        public static byte[] zCreateImgCode(string aCode)
        {
            //生成BitMap图像
            using (var bitImg = new System.Drawing.Bitmap(aCode.Length * 12 + 12, 22))
            {
                using (System.Drawing.Graphics graph = System.Drawing.Graphics.FromImage(bitImg))
                {
                    //生成随机生成器
                    Random random = new Random();
                    //清空图片背景
                    graph.Clear(System.Drawing.Color.White);
                    //画图片的背景噪音线
                    for (int i = 0; i < 25; i++)
                    {
                        int x1 = random.Next(bitImg.Width);
                        int x2 = random.Next(bitImg.Width);
                        int y1 = random.Next(bitImg.Height);
                        int y2 = random.Next(bitImg.Height);
                        graph.DrawLine(new System.Drawing.Pen(System.Drawing.Color.LightBlue), x1, x2, y1, y2);
                    }
                    System.Drawing.Font font = new System.Drawing.Font("Courier New", 14, (System.Drawing.FontStyle.Bold | System.Drawing.FontStyle.Italic));
                    System.Drawing.Drawing2D.LinearGradientBrush brush = new System.Drawing.Drawing2D.LinearGradientBrush(new System.Drawing.Rectangle(0, 0, bitImg.Width, bitImg.Height), System.Drawing.Color.Green, System.Drawing.Color.Red, 1.2f, true);
                    graph.DrawString(aCode, font, brush, 3, 2);
                    //画图片的前景噪音点
                    /*
                    for (int i = 0; i < 100; i++)
                    {
                        int x = random.Next(bitImg.Width);
                        int y = random.Next(bitImg.Height);
                        bitImg.SetPixel(x, y, System.Drawing.Color.FromArgb(random.Next()));

                    }
                    */
                    //画图片的边框线
                    graph.DrawRectangle(new System.Drawing.Pen(System.Drawing.Color.LightBlue), 0, 0, bitImg.Width - 1, bitImg.Height - 1);
                    using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
                    {
                        //将图像保存到指定流
                        bitImg.Save(ms, System.Drawing.Imaging.ImageFormat.Gif);
                        //输出图片流
                        return ms.ToArray();
                    }
                }
            }
        }
        #endregion

        #region Base64
        /// <summary>
        /// 字符串转Base64编码字符串
        /// </summary>
        /// <param name="txt">要转换的字符串</param>
        /// <param name="encoding">编码方式</param>
        /// <returns></returns>
        public static string jToBase64(this string txt, System.Text.Encoding encoding)
        {
            txt = txt ?? "";
            if (txt.Length > 0)
            {
                var bts = encoding.GetBytes(txt);
                txt = Convert.ToBase64String(bts);
            }
            return txt;
        }
        /// <summary>
        /// 字符串转Base64编码字符串（UTF8编码）
        /// </summary>
        /// <param name="txt">要转换的字符串</param>        
        /// <returns></returns>
        public static string jToBase64(this string txt)
        {
            return txt.jToBase64(System.Text.Encoding.UTF8);
        }
        /// <summary>
        /// Base64编码字符串转字符串
        /// </summary>
        /// <param name="base64Txt">Base64编码字符串</param>
        /// <param name="encoding">编码方式</param>
        /// <returns></returns>
        public static string jFromBase64(this string base64Txt, System.Text.Encoding encoding)
        {
            base64Txt = base64Txt ?? "";
            if (base64Txt.Length > 0)
            {
                var bts = Convert.FromBase64String(base64Txt);
                base64Txt = encoding.GetString(bts);
            }
            return base64Txt;
        }
        /// <summary>
        /// Base64编码字符串转字符串（UTF8编码）
        /// </summary>
        /// <param name="base64Txt">Base64编码字符串</param>
        /// <returns></returns>
        public static string jFromBase64(this string base64Txt)
        {
            return base64Txt.jFromBase64(System.Text.Encoding.UTF8);
        }

        /// <summary>
        /// Base64字符串转URL安全的参数
        /// </summary>
        /// <param name="base64Txt"></param>
        /// <returns></returns>
        public static string jToSafeBase64(this string base64Txt)
        {
            return base64Txt.jTrim().Replace("+", "-").Replace("/", "_").TrimEnd('=');
        }
        /// <summary>
        /// URL安全的Base64字符串转实际Base64
        /// </summary>
        /// <param name="base64Txt"></param>
        /// <returns></returns>
        public static string jFromSafeBase64(this string base64Txt)
        {
            var str = base64Txt.jTrim().Replace("-", "+").Replace("_", "/");
            var len = str.Length % 4;
            if (len == 2) str += "==";
            else if (len == 3) str += "=";
            return str;
        }
        #endregion

        #region AES/128位/CBC/PKCS7
        /// <summary>
        /// 将16进制字符串转byte数组（每两位作为一个字节）
        /// </summary>
        /// <param name="hex"></param>
        /// <returns></returns>
        public static byte[] jPackHex(this string hex)
        {
            int len = hex.Length >> 1;
            byte[] buffer = new byte[len];
            short k = 0;
            for (int i = 0, j = 0; i < len; i++, j = i << 1)
            {
                k = Convert.ToInt16(hex.Substring(j, 2), 16);
                buffer[i] = (byte)(k & 0xff);
            }
            return buffer;
        }
        /// <summary>
        /// AES/128位/CBC/PKCS7 加密，返回加密后的base64字符串
        /// </summary>
        /// <param name="strToEncrypt">要解密的字符串</param>
        /// <param name="keyBytes">密钥（16位）</param>
        /// <param name="ivBytes">初始化向量（16位）</param>
        /// <param name="errMsg">错误信息，正常为null，否则为异常信息</param>
        /// <returns>加密后的base64字符串</returns>
        public static string jAES128Encrypt(this string strToEncrypt, byte[] keyBytes, byte[] ivBytes, out string errMsg)
        {
            errMsg = null;
            string result = null;
            try
            {
                using (System.Security.Cryptography.RijndaelManaged rijndaelCipher = new System.Security.Cryptography.RijndaelManaged())
                {
                    rijndaelCipher.KeySize = 128;
                    rijndaelCipher.BlockSize = 128;
                    rijndaelCipher.Key = keyBytes;
                    rijndaelCipher.IV = ivBytes;
                    rijndaelCipher.Mode = System.Security.Cryptography.CipherMode.CBC;
                    rijndaelCipher.Padding = System.Security.Cryptography.PaddingMode.PKCS7;
                    using (System.Security.Cryptography.ICryptoTransform transform = rijndaelCipher.CreateEncryptor())
                    {
                        byte[] plainText = Encoding.UTF8.GetBytes(strToEncrypt);
                        byte[] cipherBytes = transform.TransformFinalBlock(plainText, 0, plainText.Length);
                        result = Convert.ToBase64String(cipherBytes);
                    }
                };
            }
            catch (Exception ex)
            {
                errMsg = ex.Message;
            }
            return result;
        }

        /// <summary>
        /// AES/128位/CBC/PKCS7 解密，返回解密后的字符串
        /// </summary>
        /// <param name="strToDecrypt">要解密的base64字符串</param>
        /// <param name="keyBytes">密钥（16位）</param>
        /// <param name="ivBytes">初始化向量（16位）</param>
        /// <param name="errMsg">错误信息，正常为null，否则为异常信息</param>
        /// <returns>解密后的字符串</returns>
        public static string jAES128Decrypt(this string strToDecrypt, byte[] keyBytes, byte[] ivBytes, out string errMsg)
        {
            errMsg = null;
            string result = null;
            try
            {
                byte[] encryptedData = Convert.FromBase64String(strToDecrypt);
                using (System.Security.Cryptography.RijndaelManaged rijndaelCipher = new System.Security.Cryptography.RijndaelManaged())
                {
                    rijndaelCipher.KeySize = 128;
                    rijndaelCipher.BlockSize = 128;
                    rijndaelCipher.Key = keyBytes;
                    rijndaelCipher.IV = ivBytes;
                    rijndaelCipher.Mode = System.Security.Cryptography.CipherMode.CBC;
                    rijndaelCipher.Padding = System.Security.Cryptography.PaddingMode.PKCS7;
                    using (System.Security.Cryptography.ICryptoTransform transform = rijndaelCipher.CreateDecryptor())
                    {
                        byte[] plainText = transform.TransformFinalBlock(encryptedData, 0, encryptedData.Length);
                        result = Encoding.UTF8.GetString(plainText);
                    }
                }
            }
            catch (Exception ex)
            {
                errMsg = ex.Message;
            }
            return result;
        }
        #endregion

        #region 图片压缩
        /// <summary>
        /// 图片字节压缩
        /// </summary>
        /// <param name="imgData"></param>
        /// <param name="maxWH"></param>
        /// <returns></returns>
        public static ResultObj<byte[]> CompressImgByte(byte[] imgData, int maxWH = 800)
        {
            var data = new ResultObj<byte[]>();
            #region 图片压缩
            try
            {
                using (System.IO.MemoryStream ms = new System.IO.MemoryStream(imgData))
                {
                    using (System.Drawing.Bitmap map = new System.Drawing.Bitmap(ms))
                    {
                        if (map.Width > maxWH || map.Height > maxWH)
                        {
                            int w = map.Width, h = map.Height;

                            if (h > maxWH)
                            {
                                w = (int)Math.Ceiling(w * (maxWH * 1.00 / h));
                                h = maxWH;
                            }

                            if (w > maxWH)
                            {
                                h = (int)Math.Ceiling(h * (maxWH * 1.00 / w));
                                w = maxWH;
                            }

                            var myImageCodecInfo = System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders().FirstOrDefault(xx => xx.MimeType == "image/jpeg");
                            if (myImageCodecInfo != null)
                            {
                                var myEncoder = System.Drawing.Imaging.Encoder.Quality;
                                var myEncoderParameters = new System.Drawing.Imaging.EncoderParameters(1);
                                var myEncoderParameter = new System.Drawing.Imaging.EncoderParameter(myEncoder, 75L);
                                myEncoderParameters.Param[0] = myEncoderParameter;
                                using (var newMap = new System.Drawing.Bitmap(map, new System.Drawing.Size(w, h)))
                                {
                                    using (var newMs = new System.IO.MemoryStream())
                                    {
                                        newMap.Save(newMs, myImageCodecInfo, myEncoderParameters);
                                        data.Obj = newMs.ToArray();
                                        newMs.Close();
                                        newMs.Close();
                                    }
                                    newMap.Dispose();
                                }
                            }
                            else
                            {
                                using (var newMap = new System.Drawing.Bitmap(map, new System.Drawing.Size(w, h)))
                                {
                                    using (var newMs = new System.IO.MemoryStream())
                                    {
                                        newMap.Save(newMs, System.Drawing.Imaging.ImageFormat.Jpeg);
                                        data.Obj = newMs.ToArray();
                                        newMs.Close();
                                        newMs.Close();
                                    }
                                    newMap.Dispose();
                                }
                            }

                        }
                        else
                        {
                            data.Obj = imgData;
                        }
                        map.Dispose();
                    }
                    ms.Close();
                    ms.Dispose();
                }
            }
            catch (Exception ex)
            {
                data.SetError(ex.Message);
            }
            #endregion
            return data;
        }
        /// <summary>
        /// 图片文件压缩
        /// </summary>
        /// <param name="filePath"></param>
        /// <param name="maxWH"></param>
        /// <returns></returns>
        public static ResultObj<byte[]> CompressImgFile(string filePath, int maxWH = 800)
        {
            var data = new ResultObj<byte[]>();
            try
            {
                if (!System.IO.File.Exists(filePath)) return data.SetError("文件不存在");
                byte[] bys;
                using (var fs = new System.IO.FileStream(filePath, System.IO.FileMode.Open))
                {
                    bys = new byte[fs.Length];
                    fs.Read(bys, 0, bys.Length);
                    fs.Close();
                }
                data = CompressImgByte(bys, maxWH);
            }
            catch (Exception ex)
            {
                data.SetError(ex.Message);
            }
            return data;
        }
        /// <summary>
        /// 图片BASE64编码压缩
        /// </summary>
        /// <param name="base64"></param>
        /// <param name="maxWH"></param>
        /// <returns></returns>
        public static ResultObj<byte[]> CompressImgBase64(string base64, int maxWH = 800)
        {
            var data = new ResultObj<byte[]>();
            byte[] bys;
            try
            {
                bys = Convert.FromBase64String(base64);
            }
            catch
            {
                return data.SetError("图片编码无效");
            }
            return CompressImgByte(bys, maxWH);
        }
        #endregion
    }
}
